import random
import socket

import struct

import time

from tornado import iostream, ioloop

import cache
from action import loginAction
from protoc.protocHead import ProtocHead

from handler import handler

class TcpClient(object):

    instance = None

    def __init__(self):
        self.io_loop = ioloop.IOLoop.instance()

        self.shutdown = False
        self.stream = None
        self.sock_fd = None
        self.is_reading = False

    @staticmethod
    def getInstance():
        if TcpClient.instance is None:
            TcpClient.instance = TcpClient()
        return TcpClient.instance


    def start(self,host,port):
        self.get_stream()
        self.stream.connect((host, port),callback=self.on_connected)
        self.onReceive()
        self.io_loop.start()


    def get_stream(self):
        self.sock_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        self.stream = iostream.IOStream(self.sock_fd)
        self.stream.set_close_callback(self.on_close)

    def on_connected(self):
        loginAction.sendTcpLoginPack()

    def on_close(self):
        print('close')
        self.io_loop.stop()

    def onReceive(self):
        self.stream.read_bytes(4096, callback=self.received,partial=True)

    def received(self,data):
        self.decode(data)
        self.onReceive()

    #解码器
    def decode(self,data):

        #包长度校验
        packLen = len(data)
        if packLen < 39:
            print('数据包不完整')
            return

        #包起始标记校验
        startTagbyte = data[:1]
        startTag = (struct.unpack('!b',startTagbyte))[0]
        if startTag != 2:
            print('非法数据包')
            return

        #包头解析
        headBytes = data[1:37]
        head = struct.unpack('!HHqbbbqqib',headBytes)
        protocHead = ProtocHead()
        protocHead.packLength = head[0]
        protocHead.cmd = head[1]
        protocHead.senderId = head[2]
        protocHead.clientOs = head[3]
        protocHead.version = head[4]
        protocHead.result = head[5]
        protocHead.time = head[6]
        protocHead.receiverId = head[7]
        protocHead.traceId = head[8]
        protocHead.ack = head[9]

        #包体解析
        bodyLength = protocHead.packLength - 38
        bodyBytes = data[37:37 + bodyLength]

        #包结束标记校验
        endTag = endTagByte = (data[37 + bodyLength:])[0]
        if endTag != 3:
            print('非法数据包')
            return

        handler.process(protocHead, bodyBytes)

    def send(self,data):
        pack = self.encode(data)
        self.stream.write(pack)


    def encode(self,pack):
        dataLen = len(pack.msgBody)
        #写入从开始标记到消息头结束的位置
        totalLen = 38 + dataLen
        nowTime = int(round(time.time() * 1000))
        traceId = int(random.uniform(0, 999999999))

        head = struct.pack('!HHqbbbqqib', totalLen, pack.cmd, cache.Cache.userInfo['id'], 1, 1, 0, nowTime, pack.receiverId,traceId, pack.ack)
        format = '!b36s' + str(dataLen) + 'sb'
        pack = struct.pack(format,2,head,pack.msgBody,3)
        return pack


class Package:
    def __init__(self):
        pass

